%{
#include <stdio.h>
#include <stdarg.h> 
#include <string.h>
#include "common.h"

extern int yyerror(char*); 
extern int yylex(), yylineno;  
extern FILE *yyin;

int yyparse(void);

#define ADD_SRC(n) addSrc(n, getSrcCode())
#define CLR_SRC()  getSrcCode()
static int parListCheck(node *np);
#define YYDEBUG 1

void printSrcCode(){
	printf("=======================================%s=============================================",getSrcCode());
}

void print_if(char* str){
    if (0){
        printf(str);
		printSrcCode();
    }
}


%}

%expect 0

%union 
{
    char*      s;
    int        i;
    double     f;
	node	   *n;
	attrib     *a;
}

%token CHAR INT SHORT LONG UCHAR UINT USHORT ULONG VOID FLOAT
%token FUNC_HEAD FUNC_DECL DATA_DECL
%token NEG_OF CALL

%token BREAK CONST CONTINUE ELSE FOR IF RETURN WHILE
%token OR_OP AND_OP EQ_OP NE_OP LE_OP GE_OP
%token INC_OP DEC_OP LEFT_OP RIGHT_OP
%token GOTO
%token ASSIGN_EXP
%token EOL LABEL
%token AASM	
%token ADD_ASSIGN SUB_ASSIGN MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN
%token LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN

%token <i> RELATIONAL_OP EQUALITY_OP
%token <s> IDENTIFIER
%token <i> INT_CONSTANT
%token <f> FLOAT_CONSTANT

%type <a> b_type func_ext_type

%type <n> comp_unit comp_unit2 decl func_def func_head var_def
%type <n> const_decl var_decl
%type <n> arrary_of_const_exp_list var_def_list
%type <n> init_val init_val_list const_init_val const_init_val_list
%type <n> identifier
%type <n> const_exp add_exp l_and_exp eq_exp rel_exp mul_exp unary_exp primary_exp exp  number l_val
%type <n> const_def const_def_list
%type <n> while_stmt other_stmt m_if_else_stmt u_if_else_stmt block_item block_item_list cond stmt block
%type <n> func_f_param func_f_param_list func_param_array_op_list 
%type <n> l_or_exp func_r_param_list 
%type <i> unary_op


%start comp_unit


%%

identifier : IDENTIFIER													{ $$ = idNode($1); free($1); }

const_exp: add_exp                                                      {
																			// print_if("\n const_exp -> add_exp \n");
																			$$ = $1;
																		}      

l_or_exp: l_and_exp                                                     {
																			// print_if("\n l_or_exp -> l_and_exp \n");
																			$$ = $1;
																		}  
| l_or_exp OR_OP l_and_exp                                              {
																			print_if("\n l_or_exp -> l_and_exp OR_OP l_and_exp \n");
																			$$ = oprNode(OR_OP, 2, $1, $3);
																		}  

l_and_exp: eq_exp                                                       {
																			// print_if("\n l_and_exp -> eq_exp \n");
																			$$ = $1;
																		}   
| l_and_exp AND_OP eq_exp                                               {
																			print_if("\n l_and_exp -> eq_exp l_and_exp AND_OP eq_exp \n");
																			$$ = oprNode(AND_OP, 2, $1, $3);
																		}             

eq_exp: rel_exp                                                         {
																			// print_if("\n eq_exp -> rel_exp \n"); 
																			$$ = $1;
																		}   
| eq_exp EQUALITY_OP rel_exp                                            {
																			// print_if("\n eq_exp -> eq_exp EQUALITY_OP rel_exp \n"); 
																			$$ = oprNode($2, 2, $1, $3);
																		}   

rel_exp: add_exp                                                        {
																			// print_if("\n rel_exp -> add_exp \n");
																			$$ = $1;
																		} 
| rel_exp RELATIONAL_OP add_exp                                         {
																			// print_if("\n rel_exp -> rel_exp RELATIONAL_OP add_exp \n");
																			$$ = oprNode($2, 2, $1, $3);
																		} 

add_exp: mul_exp                                                        {
																			// print_if("\n add_exp -> mul_exp \n");
																			$$ = $1;
																		}   
| add_exp '+' mul_exp                                                   {
																			// print_if("\n add_exp -> add_exp '+' mul_exp \n");
																		    $$ = oprNode('+', 2, $1, $3);
																		}   
| add_exp '-' mul_exp                                                   {
																			// print_if("\n add_exp -> add_exp '-' mul_exp \n");
																		    $$ = oprNode('-', 2, $1, $3);
																		}   

mul_exp: unary_exp                                                      {
																			// print_if("\n mul_exp -> unary_exp \n");
																			$$ = $1;
																		}      
| mul_exp '*' unary_exp                                                 {
																			// print_if("\n mul_exp -> mul_exp '*' unary_exp \n");
																			$$ = oprNode('*', 2, $1, $3);
																		} 
| mul_exp '/' unary_exp                                                 {
																			// print_if("\n mul_exp -> mul_exp '/' unary_exp \n");
																			$$ = oprNode('/', 2, $1, $3);
																		} 
| mul_exp '%' unary_exp                                                 {
																			// print_if("\n mul_exp -> mul_exp '%' unary_exp \n");
																			$$ = oprNode('%', 2, $1, $3);
																		}  

func_r_param_list: exp 													{ $$ = makeList($1); }
| func_r_param_list ',' exp												{ $$ = appendList($1, $3); }

unary_op: '+'                                                           {
																			print_if("\n unary_op -> '+' \n");
																			$$ = 0;
																		} 
| '-'                                                                   {
																			print_if("\n unary_op -> '-' \n");
																			$$ = NEG_OF;
																		}    
| '!'                                                                   {
																			print_if("\n unary_op -> '!' \n");
																			$$ = '!';
																		}   

unary_exp: primary_exp                                                  {
																			// print_if("\n unary_exp -> primary_exp \n");
																			$$ = $1;
																		}                                        
| identifier '('  ')'                                                   {
																			// print_if("\n unary_exp -> identifier '('  ')' \n");
																			$$ = oprNode(CALL, 2, $1, NULL);
																			ADD_SRC($$);
																		}                                     
| identifier '(' func_r_param_list ')'                                  {
																			// print_if("\n unary_exp -> identifier '(' func_r_param_list ')' \n");
																			$$ = oprNode(CALL, 2, $1, $3);
																		}                                    
| unary_op unary_exp                                                    {
																			// print_if("\n unary_exp -> unary_op unary_exp \n");
																			$$ = oprNode($1, 1, $2);
																		}                                    

number: INT_CONSTANT                                                    {
																			// print_if("\n number -> INT_CONSTANT \n");
																			$$ = conNode($1, INT);
																		}
| FLOAT_CONSTANT                                                        {
																			print_if("\n number -> FLOAT_CONSTANT \n");
																			$$ = conNodeF($1, FLOAT);
																		}

primary_exp: '(' exp ')'                                                {
																			// print_if("\n primary_exp -> '(' exp ')' \n");
																			$$ = $2;
																		}  
| l_val                                                                 {
																			// print_if("\n primary_exp -> l_val \n");
																			$$ = $1;
																		}     
| number                                                                {
																			// print_if("\n primary_exp -> number \n");
																			$$ = $1;
																		}    

l_val: identifier                                                       {
																			// print_if("\n l_val -> identifier \n");
																			$$ = $1;
																		} 
| l_val '[' exp ']'                                                     {
																			print_if("\n l_val -> identifier l_val_array_of \n");
																			$$ = oprNode('[', 2, $1, $3);
																		} 

cond: l_or_exp                                                          {
																			//print_if("\n cond -> l_or_exp \n");
																			$$ = $1;
																			ADD_SRC($$);
																		}

exp: add_exp                                                            {
																			// print_if("\n exp -> add_exp \n");
																			$$ = $1;
																			//ADD_SRC($$);
																		}

stmt: m_if_else_stmt                                                    {
																			print_if("\n stmt -> m_if_else_stmt \n");
																			$$ = $1;
																		}
| u_if_else_stmt                                                        {
																			print_if("\n stmt -> u_if_else_stmt \n");
																			$$ = $1;
																		}
| while_stmt															{
																			$$ = $1;
																		}

while_stmt: WHILE '(' cond ')' stmt                                     {
																			print_if("\n while_stmt -> WHILE '(' cond ')' stmt \n");
																			$$ = oprNode(WHILE, 2, $3, $5);
																		}

other_stmt: ';'                                                         {
																			print_if("\n other_stmt -> ';' \n");
																			$$ = oprNode(';', 0);
																		}
| l_val '=' exp ';'                                                     {
																			// print_if("\n other_stmt -> l_val '=' exp ';' \n");
																			$$ = oprNode('=', 2, $1, $3);
																			ADD_SRC($$);
																			
																		}
| exp ';'                                                               {
																			print_if("\n other_stmt -> exp ';' \n");
																			
																			$$ = $1;
																		}
| block                                                                 {
																			print_if("\n other_stmt -> block \n");
																			
																			$$ = $1;
																		}    
| BREAK ';'                                                             {
																			print_if("\n other_stmt -> BREAK ';' \n");
																			
																			$$ = oprNode(BREAK, 0); 
																		}    
| CONTINUE ';'                                                          {
																			print_if("\n other_stmt -> CONTINUE ';' \n");
																			
																			$$ = oprNode(CONTINUE, 0);   
																		}    
| RETURN ';'                                                            {
																			// print_if("\n other_stmt -> RETURN ';' \n");
																			$$ = oprNode(RETURN, 0); 
																			ADD_SRC($$);																			
																		}    
| RETURN exp ';'                                                        {
																			print_if("\n other_stmt -> RETURN exp ';' \n");
																			$$ = oprNode(RETURN, 1, $2);
																			ADD_SRC($$);																			
																		}        

m_if_else_stmt: IF '(' cond ')' m_if_else_stmt ELSE m_if_else_stmt      {
																			print_if("\n m_if_else_stmt -> IF '(' cond ')' m_if_else_stmt ELSE m_if_else_stmt \n");
																			$$ = oprNode(IF, 3, $3, $5, $7);
																		}
| other_stmt                                                            {
																			print_if("\n m_if_else_stmt -> other_stmt \n");
																			$$ = $1;
																		}

u_if_else_stmt: IF '(' cond ')' stmt                                    {
																			print_if("\n u_if_else_stmt -> IF '(' cond ')' stmt \n");
																			$$ = oprNode(IF, 2, $3, $5); 
																		}
| IF '(' cond ')' m_if_else_stmt ELSE u_if_else_stmt                    {
																			print_if("\n u_if_else_stmt -> IF '(' cond ')' stmt m_if_else_stmt ELSE u_if_else_stmt \n");
																			$$ = oprNode(IF, 3, $3, $5, $7); 
																		}

block_item: decl                                                        {
																			print_if("\n block_item -> decl \n");
																			$$ = $1;
																		}
| stmt                                                                  {
																			print_if("\n block_item -> stmt \n");
																			$$ = $1;
																		}

block_item_list: block_item                                             {
																			print_if("\n block_item_list -> * empty * \n");
																			$$ = makeList($1);
																			$$ = appendList($$, oprNode(';', 0));
																		}
| block_item_list block_item                                            {
																			print_if("\n block_item_list -> block_item_list block_item \n");
																			$$ = appendList($1, $2);
																			$$ = appendList($$, oprNode(';', 0));
																		}

block: '{' '}'				                                            {
																			print_if("\n block -> '{' block_item_list '}' \n");
																			$$ = oprNode('{', 0);    
																		}
| '{' block_item_list '}'												{
																			print_if("\n block -> '{' block_item_list '}' \n");
																			$$ = oprNode('{', 1, $2);   
																		}

func_param_array_op_list: '[' ']'                                       {
																			print_if("\n func_param_array_op_list -> '[' ']' \n");
																			$$ = makeList(conNode(0, INT));
																		}
| func_param_array_op_list '[' exp ']'                                  {
																			print_if("\n func_param_array_op_list -> '[' exp ']' \n");
																			$$ = appendList($1, $3);
																		}

b_type: INT                                                             {
																			// print_if("\n b_type -> INT \n");
																			$$ = newAttr(INT);
																		}
| FLOAT                                                                 {
																			print_if("\n b_type -> FLOAT \n");
																			$$ = newAttr(FLOAT);
																		}

func_f_param: b_type identifier                                         {
																			// print_if("\n func_f_param -> b_type identifier \n");
																			$$ = $2;
																			$$->id.attr = $1;
																		}
| b_type identifier func_param_array_op_list                            {
																			print_if("\n func_f_param -> b_type identifier func_param_array_op_list \n");
																			$$ = $2;
																			$$->id.attr = $1;
																			$$->id.dim = $3;
																		}

func_f_param_list: func_f_param                                         {
																			// print_if("\n func_f_param_list -> func_f_param \n");
																			$$ = makeList($1);
																		}
| func_f_param_list ',' func_f_param                                    {
																			// print_if("\n func_f_param_list -> func_f_param_list ',' func_f_param \n");
																			$$ = appendList($1, $3);
																		}
				 
func_ext_type: VOID                                                     {
																			// print_if("\n func_ext_type -> VOID \n");
																			$$ = newAttr(VOID);
																		}
																		
func_head : identifier '('  ')'      		                         	{
																			// print_if("\n func_head: b_type identifier '('  ')'  \n");
																			$$ = oprNode(FUNC_HEAD, 1, $1);
																			ADD_SRC($$);
																		} 
|  identifier '(' func_f_param_list  ')' 		                   		{
																			// print_if("\n func_head: b_type identifier '(' func_f_param_list ')'  \n");
																			$$ = oprNode(FUNC_HEAD, 2, $1, $3);
																			ADD_SRC($$);
																		}
																		

func_def: b_type func_head block                       					{
																			print_if("\n func_def: b_type identifier '('  ')' block \n");
																	        $$ = oprNode(FUNC_DECL, 2, $2, $3); 
																			$$->opr.attr = $1;
																		} 

| func_ext_type func_head block                       					{
																			print_if("\n func_def: b_type identifier '('  ')' block \n");
																	        $$ = oprNode(FUNC_DECL, 2, $2, $3); 
																			$$->opr.attr = $1;
																		} 

init_val_list: init_val                                                 {
																			print_if("\n init_val_list: init_val \n");
																			$$ = makeList($1);
																		}
| init_val_list ',' init_val                                            {
																			print_if("\n init_val_list: init_val_list ',' init_val \n");
																			$$ = appendList($1, $3);
																		}

init_val: exp                                                           {
																			$$ = $1;
																		}
| '{' '}'                                                               {
																			print_if("\n init_val -> '{' '}' \n");
																			$$ = makeList(NULL);
																		}
| '{' init_val_list '}'                                                 {
																			print_if("init_val -> '{' init_val_list '} '\n");
																			$$ = $2;
																		}

var_def: identifier arrary_of_const_exp_list                            {
																			// print_if("\n var_def: identifier arrary_of_const_exp_list \n");
																			$$ = $1;
																			$$->id.dim = $2;
																		}
| identifier arrary_of_const_exp_list '=' init_val                      {
																			// print_if("\n var_def: identifier arrary_of_const_exp_list '=' init_val  \n");
																			$$ = $1;
																			$$->id.dim = $2;
																			$$->id.init = $4;
																		}

var_def_list: var_def                                                   {
																			// print_if("\n var_def_list: var_def \n");
																			$$ = makeList($1);
																	    }
| var_def_list ',' var_def                                              {
																			// print_if("\n var_def_list: var_def_list ',' var_def \n");
																			$$ = appendList($1, $3);
																		}

var_decl: b_type var_def_list ';'                                       {
																			// print_if("\n var_decl -> b_type var_def_list ';' \n");
																			$$ = oprNode(DATA_DECL, 1, $2); 
																			$$->opr.attr = $1;
																			ADD_SRC($$);
																		}

const_init_val_list: const_init_val                                     {
																			print_if("\n const_init_val_list -> const_init_val \n");
																			$$ = makeList($1);
																		}
| const_init_val_list ',' const_init_val                                {
																			print_if("\n const_init_val_list -> const_init_val_list ',' const_init_val \n");
																			$$ = appendList($1, $3);
																		}

const_init_val: const_exp                                               {
																			print_if("\n const_init_val -> const_exp  \n");
																			$$ = $1;
																		}
| '{' '}'                                                               {
																			print_if("\n const_init_val -> '{' '}'  \n");
																			$$ = makeList(conNode(0, INT));
																		}
| '{' const_init_val_list '}'                                           {
																			print_if("\n const_init_val -> '{' const_init_val_list '}' \n");
																			$$ = $2;
																		}

arrary_of_const_exp_list:                                               {
																			// print_if("\n arrary_of_const_exp_list -> * empty * \n");
																			$$ = NULL;
																		}
| arrary_of_const_exp_list '[' const_exp ']'                            {
																			// print_if("\n arrary_of_const_exp_list -> arrary_of_const_exp_list '[' const_exp ']' \n");
																			$$ = appendList($1, $3);
																		}

const_def: identifier arrary_of_const_exp_list '=' const_init_val       {
																			print_if("\n const_def -> identifier arrary_of_const_exp_list '=' const_init_val \n");
																			$$ = $1;
																			$$->id.dim = $2;
																			$$->id.init = $4;
																		}

const_def_list: const_def                                               {
																			print_if("\n const_def_list -> const_def \n");
																			$$ = makeList($1);
																		}
| const_def_list ',' const_def                                          {
																			print_if("\n const_def_list -> const_def_list ',' const_def \n");
																			$$ = appendList($1, $3);
																		}

const_decl: CONST b_type const_def_list ';'                             {
																			print_if("\n const_decl -> CONST b_type const_def_list ';' \n");
																			$$ = oprNode(DATA_DECL, 1, $3); 
																		    $$->opr.attr = $2;
																			//$$->opr.attr->dataBank = CONST;
																			//ADD_SRC($$);
																		}
| CONST const_def_list ';'												{ yyerror("please give variable a type definenetion"); }

decl: const_decl                                                        {
																			print_if("\n decl -> const_decl  \n"); 
																			$$ = $1;
																		}
| var_decl                                                              {
																			print_if("\n decl -> var_decl    \n"); 
																			$$ = $1;
																		}
                                                                        
comp_unit2: decl                                                         {
																		    $$ = makeList($1);
																			print_if("\n comp_unit2 -> decl     \n");
																		}
| func_def                                                              {
																		    $$ = makeList($1);
																			print_if("\n comp_unit2 -> func_def \n");
																		}
| comp_unit2 decl                                                        {
																		    $$ = appendList($1, $2);
																			print_if("\n comp_unit2 -> comp_unit2 decl     \n");
																		}
| comp_unit2 func_def                                                    {
																		    $$ = appendList($1, $2);
																			print_if("\n comp_unit2 -> comp_unit2 func_def \n");
																		}
																		

comp_unit: comp_unit2                                                   {
																		    progUnit = $$;
																			print_if("\n comp_unit -> comp_unit2     \n");
																		}


